/******************************************************************************
This file is part of AppKit.
Project: appkit
Author : FergusZeng
Email  : cblock@126.com
git	   : https://gitee.com/newgolo/appkit.git
*******************************************************************************
MIT License

Copyright (c) 2022 cblock@126.com

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#pragma once

#include <atomic>
#include <map>
#include <set>
#include <memory>

#include "appkit/basetype.h"
#include "appkit/thread.h"
/**
 * @file fsmachine.h
 * @brief 状态机
 * @code 用法
 *    //状态机用法:
 *    //1.实例化StateHandler.
 *    //2.将状态处理器注册到状态机
 *    //3.设置初始状态,启动状态机.
 *    //4.运行状态处理.
 *    FSMachine stateMachine;
 *    stateMachine.registerState(0, std::bind(&Class::handleStateA, this));
 *    stateMachine.registerState(1,std::bind(&Class::handleStateB, this));
 *    stateMachine.setState(0);
 *    while(1)
 *    {
 *        stateMachine.processState();
 *        Thread::msleep(100);
 *    }
 * @endcode
 */

namespace appkit {

/**
 * @class FSListener
 * @brief 状态监听器
 * @note 当状态机状态发生改变时,通知所有状态监听器
 */
class FSListener {
public:
    virtual void onStateChanged(int state) = 0;
};

/**
 * @class FSMachine
 * @brief 状态机
 */
class FSMachine {
    DECL_CLASSMETA(FSMachine)

public:
    FSMachine();
    virtual ~FSMachine();
    /**
     * @brief 初始化状态
     * @param state
     * @return true
     * @return false
     */
    bool initState(int state);
    /**
     * @brief 注册状态处理器
     * @param state,必须大于等于0，负数为非法状态
     * @param stateHandler
     * @return true
     * @return false
     */
    bool addState(int state, std::function<int(void)> stateHandler);
    /**
     * @brief 注册状态监听器
     * @param listener
     */
    void addListener(std::shared_ptr<FSListener> listener);

    /**
     * @brief 获取当前状态
     * @return int
     */
    int getState();

    /**
     * @brief 处理当前状态
     */
    void processState(void);

private:
    std::atomic<int> m_currState{-1};
    std::map<int, std::function<int(void)>> m_stateHandlerMap;
    std::set<std::shared_ptr<FSListener>> m_stateListenerSet;
};

}  // namespace appkit
